package compiler;

import compiler.patch.CompilerChecker;
import compiler.patch.CustomToolProvider;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;
import javax.tools.*;

/**
 * @author WL
 */
public class DynamicJava 
{
    public static JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    
    /**
     * Used for compilations that do not require any state to be saved.
     * @param sourceCode
     * @param outputStream
     * @return
     * @throws IOException 
     */
    public static ClassFileManager getClassManager(String filename, String sourceCode,
            OutputStream outputStream) throws IOException
    {
        return getClassManager(filename, sourceCode,
            outputStream, null, null);
    }
    
    public static ClassFileManager getClassManager(String filename, String sourceCode,
            OutputStream outputStream, Iterable<String> options, Iterable<String> classNames) throws IOException
    {
        //patch for systems that do not have tools.jar in their JRE
        if (DynamicJava.compiler == null)
        {
            if (CustomToolProvider.getSystemJavaCompiler() != null)
                DynamicJava.compiler =  CustomToolProvider.getSystemJavaCompiler();
            else
            {
                CompilerChecker.getInstance().check();
            }
        }
        
        //writer to write all output messages to the outputstream
        OutputStreamWriter writer = new OutputStreamWriter(outputStream);
        
        // We get an instance of JavaCompiler. Then
        // we create a file manager
        // (our custom implementation of it)        
        ClassFileManager fileManager = new
            ClassFileManager(compiler
                .getStandardFileManager(null, null, null));

        // Dynamic compiling requires specifying
        // a list of "files" to compile. In our case
        // this is a list containing one "file" which is in our case
        // our own implementation (see details below)
        List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
        if (filename != null)
        {
            int periodIndex = filename.lastIndexOf(".");
            if (periodIndex >= 0)
                filename = filename.substring(0, periodIndex);
        }
        jfiles.add(new StringJavaFileObject(filename == null ? "" : filename, sourceCode));
        
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

        // We specify a task to the compiler. Compiler should use our file
        // manager and our list of "files".
        // Then we run the compilation with call()
        boolean status = compiler.getTask(writer, fileManager, diagnostics, options,
            classNames, jfiles).call();
        
        if (!status)
        {
            for (Diagnostic diagnostic : diagnostics.getDiagnostics())
                writer.append(String.format("line %s, col %s: %s\n", diagnostic.getLineNumber(), diagnostic.getColumnNumber(), diagnostic.getMessage(null)));
        }
        
        writer.close();
        
        return fileManager;        
    }
}
